#pragma once

#include <string>

#include <sys/select.h>

#include "Socket.hpp"

using namespace std;
using namespace SocketModule;

class SelectServer
{
    static const int default_max_size = 1024;
    static const int default_fd = -1;

public:
    SelectServer(uint16_t port)
        : _listensocket(make_shared<TcpSocket>(port)),
          _port(port),
          _isrunning(false)
    {
        // 初始化listensocket
        _listensocket->BuildSocket(SockType::LISTEN_SOCK);

        // 初始化辅助数组
        for (int i = 0; i < default_max_size; i++)
        {
            _fds[i] = default_fd;
        }

        // 把listensocket对应的fd，添加到关心数组中
        _fds[0] = _listensocket->GetSockfd();
    }
    void Accept()
    {
        // 获取新链接
        uint32_t ip_client;
        uint16_t port_client;
        SockPtr newsock = _listensocket->Accept(ip_client, port_client);
        int newfd = newsock->GetSockfd();

        // 遍历寻找空位添加，需要关心的新链接的fd
        int j = 0;
        for (j = 0; j < default_max_size; j++)
        {
            if (_fds[j] == default_fd) // 如果有空位
            {
                // 添加要关心读事件的fd
                LOG(LogLevel::DEBUG) << "添加关心fd成功，fd: " << newfd;
                _fds[j] = newfd;
                break;
            }
        }
        if (j >= default_max_size)
        {
            LOG(LogLevel::DEBUG) << "能关心的fd已满，无法再添加";
            newsock->Close();
        }
    }
    void Recv(int &rfd)
    {
        char rbuf[1024];
        // 开始读取请求
        int rval = recv(rfd, rbuf, sizeof(rbuf), 0);
        if (rval > 0)
        {
            rbuf[rval] = '\0';
            LOG(LogLevel::DEBUG) << "客户端发来信息，fd: " << rfd << "# " << rbuf;

            string out = "server# ";
            out += rbuf;
            // 回复客户端
            send(rfd, out.c_str(), out.size(), 0);
        }
        else if (rval == 0)
        {
            LOG(LogLevel::DEBUG) << "客户端断开连接，fd: " <<rfd;
            close(rfd);
            rfd = default_fd; // 关闭fd，留出空位
        }
        else
        {
            LOG(LogLevel::ERROR) << "recv error";
        }
    }
    void Start()
    {
        if (_isrunning == true)
        {
            return;
        }
        _isrunning = true;
        while (true)
        {
            // 要关心的最大的fd
            int max_fd = default_fd;
            // 要关心的读fd集合
            fd_set rfd_set;
            FD_ZERO(&rfd_set); // 清空一下
            for (int i = 0; i < default_max_size; i++)
            {
                if (_fds[i] == default_fd)
                {
                    // 为无效fd就跳过
                    continue;
                }
                if (_fds[i] > max_fd)
                {
                    // 更新最大值
                    max_fd = _fds[i];
                }
                // 添加要关心读事件的fd
                // LOG(LogLevel::DEBUG) << "添加关心fd成功，fd: " <<_fds[i];
                FD_SET(_fds[i], &rfd_set);
            }
            LOG(LogLevel::DEBUG) << "max_fd: " << max_fd;

            int n = select(max_fd + 1, &rfd_set, nullptr, nullptr, nullptr);
            if (n > 0) // 有fd就绪
            {
                // 遍历检查  哪些关心的fd就绪了
                for (int i = 0; i < default_max_size; i++)
                {
                    if (_fds[i] == default_fd)
                    {
                        // 为无效fd就跳过
                        continue;
                    }
                    if (FD_ISSET(_fds[i], &rfd_set)) // 如果关心的fd就绪
                    {
                        // 如果是listensocketfd就绪
                        if (_fds[i] == _listensocket->GetSockfd())
                        {
                            LOG(LogLevel::DEBUG) << "listensocketfd: " << _fds[i] << "就绪";
                            // 去获取新连接
                            Accept();
                        }
                        else // 如果是普通fd就绪
                        {
                            LOG(LogLevel::DEBUG) << "fd: " << _fds[i] << "就绪";
                            Recv(_fds[i]);
                        }
                    }
                }
            }
            else if (n == 0)
            {
                LOG(LogLevel::ERROR) << "没有fd就绪";
            }
            else
            {
                LOG(LogLevel::ERROR) << "select error";
            }
        }
        _isrunning = false;
    }
    void Stop()
    {
        _isrunning = false;
    }
    ~SelectServer()
    {
        _listensocket->Close();
    }

private:
    uint16_t _port;
    int _fds[default_max_size]; // 存储需要关心的所以fd
    SockPtr _listensocket;
    bool _isrunning;
};